//
//  ViewController.m
//  GCD-interView
//
//  Created by 汪贻峰 on 2019/9/19.
//  Copyright © 2019 ML. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, assign) int count;
//票数
@property (nonatomic, assign) int ticketNumber;
@property (nonatomic, strong) dispatch_semaphore_t  semaphore;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.count = 0;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //同步并发
//    [self createSyncQueue];
    
    //异步并发
//    [self createAsyncQueue];
    
    //同步串行
//    [self createSyncQueueChuanXing];
    
    //异步串行
//    [self createAsyncQueueChuanXing];
    
    //其他线程执行同步主队列
//    [NSThread detachNewThreadSelector:@selector(createSyncQueueMainQueue) toTarget:self withObject:nil];
    
    //主线程执行同步主队列
//    [self createSyncQueueMainQueue];
    
    //异步主队列
//    [self createAsyncQueueMainQueue];
    
    //线程间通讯
//    [self gcdCommunication];

    //栅栏函数
//    [self gcdBarrier];
    
    //延迟执行
//    [self gcdDelay];
    
    //一次性代码
//    [self gcdOnce];
    
    //多次执行,快速迭代
//    [self gcdApply];
    
    //组队列监听完成
//    [self gcdGroup];
    
    //队列等待
//    [self gcdWaitGroup];
    
    //组队列进入以及离开任务
//    [self gcdAddOrMiunsGroup];
    
    //信号量实现异步改同步
//    [self gcdSemaphore];

    //非线程安全的卖票
//    [self initSaleTicket];
    
    //线程安全卖票
    [self initSafeSaleTicket];
    
}
//同步并发队列
- (void)createSyncQueue{
    
    NSLog(@"currentThread = %@",[NSThread currentThread]);
    
    dispatch_queue_t queue = dispatch_queue_create("ml.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_sync - currentThread 1 = %@",[NSThread currentThread]);

    });
    
    dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_sync - currentThread 2 = %@",[NSThread currentThread]);
        
    });
    
    dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_sync - currentThread 3 = %@",[NSThread currentThread]);
    });
    
    NSLog(@"syncConcurrent---end");

}
//异步并发队列
- (void)createAsyncQueue{
    
    NSLog(@"begin");

    NSLog(@"currentThread = %@",[NSThread currentThread]);

    dispatch_queue_t queue = dispatch_queue_create("ml.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_sync - currentThread 1 = %@",[NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_sync - currentThread 2 = %@",[NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_sync - currentThread 3 = %@",[NSThread currentThread]);
        
    });
    
    NSLog(@"end");

}
//同步串行
-(void)createSyncQueueChuanXing{
    
    NSLog(@"begin");
    
    NSLog(@"currentThread = %@",[NSThread currentThread]);
    
    dispatch_queue_t queue = dispatch_queue_create("ml.queue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createSyncQueueChuanXing - currentThread 1 = %@",[NSThread currentThread]);
        
    });
    
    dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createSyncQueueChuanXing - currentThread 2 = %@",[NSThread currentThread]);
        
    });
    
    dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createSyncQueueChuanXing - currentThread 3 = %@",[NSThread currentThread]);
        
    });
    
    NSLog(@"end");
    
}
//异步串行
-(void)createAsyncQueueChuanXing{
    
    NSLog(@"begin");
    
    NSLog(@"currentThread = %@",[NSThread currentThread]);
    
    dispatch_queue_t queue = dispatch_queue_create("ml.queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createAsyncQueueChuanXing - currentThread 1 = %@",[NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createAsyncQueueChuanXing - currentThread 2 = %@",[NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createAsyncQueueChuanXing - currentThread 3 = %@",[NSThread currentThread]);
        
    });
    
    NSLog(@"end");
    
}
//同步主队列
-(void)createSyncQueueMainQueue{
    
    NSLog(@"begin");
    
    NSLog(@"currentThread = %@",[NSThread currentThread]);
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createAsyncQueueMainQueue - currentThread 1 = %@",[NSThread currentThread]);
        
    });
    
    dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createAsyncQueueMainQueue - currentThread 2 = %@",[NSThread currentThread]);
        
    });
    
    dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createAsyncQueueMainQueue - currentThread 3 = %@",[NSThread currentThread]);
        
    });
    
    NSLog(@"end");
    
}

//异步主队列
-(void)createAsyncQueueMainQueue{
    
    NSLog(@"begin");
    
    NSLog(@"currentThread = %@",[NSThread currentThread]);
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createAsyncQueueMainQueue - currentThread 1 = %@",[NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createAsyncQueueMainQueue - currentThread 2 = %@",[NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"createAsyncQueueMainQueue - currentThread 3 = %@",[NSThread currentThread]);
        
    });
    
    NSLog(@"end");
    
}

- (void)GCD{
    //const char * _Nullable label 队列的唯一标识
    //dispatch_queue_attr_t  _Nullable attr 队列类型: 串行/并发
    
    //DISPATCH_QUEUE_SERIAL 串行
    //DISPATCH_QUEUE_CONCURRENT 并发
    
    //创建一个串行队列
    dispatch_queue_t chuanQueue =  dispatch_queue_create("ml.createQueue", DISPATCH_QUEUE_SERIAL);
    
    //创建一个并发队列
    dispatch_queue_t BingQueue1 = dispatch_queue_create("ml.createContent", DISPATCH_QUEUE_CONCURRENT);
    
    //主队列,特殊的串行
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
    //全局并发队列,第一个参数:优先级
    /*#define DISPATCH_QUEUE_PRIORITY_HIGH 2
     #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
     #define DISPATCH_QUEUE_PRIORITY_LOW (-2)
     #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
     */
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
#pragma mark - :任务创建
    
    //同步任务
    //dispatch_queue_t queue : 队列
    //dispatch_block_t block : 要执行的方法
    //同步,串行
    dispatch_sync(chuanQueue, ^{
        //需要执行的事情
        
    });
    //同步,并发行
    dispatch_async(BingQueue1, ^{
        
    });
    
    //异步任务,串行
    dispatch_async(chuanQueue, ^{
        //异步执行的事情
        
        
    });
    
    //异步任务,并发
    dispatch_async(BingQueue1, ^{
        //异步执行的事情
        
    });
    
    //串行,主队列 ,死锁
    dispatch_sync(dispatch_get_main_queue(), ^{
        
    });
    
    //异步主队列
    dispatch_async(dispatch_get_main_queue(), ^{
        
    });
    
    
}

//GCD线程间通讯
- (void)gcdCommunication{
    //主线程
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
    //异步全局并发队列
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
       
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_get_global_queue ---  %@",[NSThread currentThread]);
        
        dispatch_async(mainQueue, ^{
            self.view.backgroundColor = [UIColor redColor];
            NSLog(@"mainQueue ---  %@",[NSThread currentThread]);
        });
        
    });
}

//GCD栅栏函数
- (void)gcdBarrier{
    
    dispatch_queue_t globalQueue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(globalQueue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"globalQueue = 1 : %@\n",[NSThread currentThread]);
    });
    dispatch_async(globalQueue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"globalQueue = 2 : %@\n",[NSThread currentThread]);
    });
    
    dispatch_barrier_async(globalQueue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"dispatch_barrier_async = 3 : %@\n",[NSThread currentThread]);
    });
    
    dispatch_async(globalQueue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"globalQueue = 4 : %@\n",[NSThread currentThread]);
    });
    dispatch_async(globalQueue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"globalQueue = 5 : %@\n",[NSThread currentThread]);
    });
    
}

//GCD延迟加载
- (void)gcdDelay{
    NSLog(@"gcdDelay = 1 : %@\n",[NSThread currentThread]);

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"gcdDelayEnd = 2 : %@\n",[NSThread currentThread]);

        self.view.backgroundColor = [UIColor yellowColor];
    });
    
}
//GCD一次执行
- (void)gcdOnce{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //只会执行一次的,线程默认是安全的
        self.count++;
        NSLog(@"dispatch_once = 2 : %@\n",[NSThread currentThread]);
        NSLog(@"count -- %d\n",self.count);

        
    });
}

//快速迭代
- (void)gcdApply{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0 );
    
    dispatch_apply(10, queue, ^(size_t i) {
        NSLog(@"%zu----%@",i,[NSThread currentThread]);
    });
    NSLog(@"%@ --- end",[NSThread currentThread]);
    
}

//组队列
- (void)gcdGroup{
    
    NSLog(@"%@ ---- begin\n",[NSThread currentThread]);

    dispatch_queue_t globale = dispatch_get_global_queue(0, 0);
   
    dispatch_group_t group = dispatch_group_create();
  
    dispatch_group_async(group, globale, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_group_async = 1 : %@\n",[NSThread currentThread]);

    });
    dispatch_group_async(group, globale, ^{
        [NSThread sleepForTimeInterval:2];

        NSLog(@"dispatch_group_async = 2 : %@\n",[NSThread currentThread]);
        
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        self.view.backgroundColor = [UIColor lightGrayColor];
        NSLog(@"dispatch_get_main_queue = 4 : %@\n",[NSThread currentThread]);
        
    });
    
    dispatch_group_async(group, globale, ^{
        [NSThread sleepForTimeInterval:2];

        NSLog(@"dispatch_group_async = 3 : %@\n",[NSThread currentThread]);
        
    });
    
    
    NSLog(@"%@ ---- end\n",[NSThread currentThread]);

}

//组队列等待
- (void)gcdWaitGroup{
    NSLog(@"%@ ---- begin\n",[NSThread currentThread]);
    
    dispatch_queue_t globale = dispatch_get_global_queue(0, 0);
    
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, globale, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_group_async = 1 : %@\n",[NSThread currentThread]);
        
    });
    dispatch_group_async(group, globale, ^{
        [NSThread sleepForTimeInterval:2];
        
        NSLog(@"dispatch_group_async = 2 : %@\n",[NSThread currentThread]);
        
    });
    
    dispatch_group_async(group, globale, ^{
        [NSThread sleepForTimeInterval:2];
        
        NSLog(@"dispatch_group_async = 3 : %@\n",[NSThread currentThread]);
        
    });
    
    //等待
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

    NSLog(@"%@ ---- end\n",[NSThread currentThread]);
}

//组队列的任务追加以及删除
- (void)gcdAddOrMiunsGroup{
    
    dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_enter(group);
    dispatch_async(globalQueue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_group_enter = 1 : %@\n",[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(globalQueue, ^{
        [NSThread sleepForTimeInterval:2];

        NSLog(@"dispatch_group_enter = 2 : %@\n",[NSThread currentThread]);
        
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(globalQueue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_group_enter = 3 : %@\n",[NSThread currentThread]);
        
        dispatch_group_leave(group);
    });
   
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    NSLog(@"%@ ---- 4 end\n",[NSThread currentThread]);

}

//信号量
- (void)gcdSemaphore{
    NSLog(@"SemaphorecurrentThear%@",[NSThread currentThread]);
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    __block int num = 1;
    //异步并发
    dispatch_async(queue, ^{
        
        [NSThread sleepForTimeInterval:2];
        NSLog(@"dispatch_async - 1 %@",[NSThread currentThread]);
        num = 20;
        //发送信号 + 1
        dispatch_semaphore_signal(semaphore);
        
    });
    
    //等待信号量
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    NSLog(@"dispatch_semaphore_t : end,number = %d,current -- %@",num,[NSThread currentThread]);

}

//不安全的线程
- (void)initSaleTicket{
    self.ticketNumber = 20;
    dispatch_queue_t beijingQueue = dispatch_queue_create("com.beijing.queue", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t shanghaiQueue = dispatch_queue_create("com.shanghai.queue", DISPATCH_QUEUE_SERIAL);
    __weak typeof(self) weakSelf = self;

    dispatch_async(beijingQueue, ^{
        [weakSelf saleTicket];
    });
    
    dispatch_async(shanghaiQueue, ^{
        [weakSelf saleTicket];
    });
    
}

- (void)saleTicket{
    while (1) {
        if (self.ticketNumber > 0) {
            self.ticketNumber --;
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票数：%d 窗口：%@", self.ticketNumber, [NSThread currentThread]]);
            [NSThread sleepForTimeInterval:0.2];
    
                }else {
                    NSLog(@"票已售完");
                    break;
        }
    }
}

//安全的线程
- (void)initSafeSaleTicket{
    
    _semaphore = dispatch_semaphore_create(1);
    
    self.ticketNumber = 20;
    dispatch_queue_t beijingQueue = dispatch_queue_create("com.beijing.queue", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t shanghaiQueue = dispatch_queue_create("com.shanghai.queue", DISPATCH_QUEUE_SERIAL);
    __weak typeof(self) weakSelf = self;
    
    dispatch_async(beijingQueue, ^{
        [weakSelf safeSaleTicket];
    });
    
    dispatch_async(shanghaiQueue, ^{
        [weakSelf safeSaleTicket];
    });
    
}

- (void)safeSaleTicket{
    
    while (1) {
        //加锁 等待解锁
        dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
        if (self.ticketNumber > 0) {
            self.ticketNumber --;
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票数：%d 窗口：%@", self.ticketNumber, [NSThread currentThread]]);
            [NSThread sleepForTimeInterval:0.2];
            
        }else {
            NSLog(@"票已售完");
//            解锁
            dispatch_semaphore_signal(_semaphore);
            break;
        }
//        解锁
        dispatch_semaphore_signal(_semaphore);
    }
}


@end
